package services

import (
	"crypto/ecdsa"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/mr-tron/base58"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"log"
	"math/big"
	"os"
	"signature-service/contract"
	"signature-service/contract/evmAbi"
	"signature-service/repositories"
	"signature-service/utils"
	"strconv"
)

// SignService 签名服务
type SignService struct{}

func NewSignService() *SignService {
	return &SignService{}
}

// GenerateAddress 生成地址
func (s *SignService) GenerateAddress(flag string) (string, string, error) {
	var privateKeyHex string
	var address string
	switch flag {
	case "TRX": // TRX地址
		privateKey, _ := crypto.GenerateKey()
		privateKeyBytes := crypto.FromECDSA(privateKey)
		publicKey := privateKey.Public()
		publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
		addrStr := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
		addrStr = "41" + addrStr[2:]
		addb, _ := hex.DecodeString(addrStr)
		firstHash := sha256.Sum256(addb)
		secondHash := sha256.Sum256(firstHash[:])
		secret := secondHash[:4]
		addb = append(addb, secret...)
		address = base58.Encode(addb)
		privateKeyHex = hexutil.Encode(privateKeyBytes)[2:]
	default:
		// 生成私钥
		privateKey, _ := crypto.GenerateKey()
		// 将私钥转换为字节切片
		privateKeyBytes := crypto.FromECDSA(privateKey)
		// 将字节切片转换为十六进制字符串
		privateKeyHex = hex.EncodeToString(privateKeyBytes)
		// 生成公钥
		publicKey := privateKey.Public().(*ecdsa.PublicKey)
		// 生成地址
		address = crypto.PubkeyToAddress(*publicKey).Hex()
	}
	privateKeyHex, err := utils.EncryptWithPublicKeyFromFile(privateKeyHex)
	if err != nil {
		return "", "", err
	}
	// 保存私钥
	var sign repositories.PrivateKeys
	sign.Address = address
	sign.PrivateKey = privateKeyHex
	sign.Type = flag
	err = sign.Insert()
	if err != nil {
		return "", "", err
	}

	return address, sign.ID, nil
}

// GetEvmSign 获取EVM签名
func (s *SignService) GetEvmSign(privateKeys repositories.PrivateKeys, to string, tokenAddress string, value string, rpcUrl string) (*types.Transaction, error) {
	if tokenAddress != "" {
		decodePrivateKey, err := utils.DecryptWithPrivateKeyFromFile(privateKeys.PrivateKey)
		if err != nil {
			return nil, err
		}

		client, err := ethclient.Dial(rpcUrl)
		if err != nil {
			return nil, err
		}

		privateKey, err := crypto.HexToECDSA(decodePrivateKey)
		if err != nil {
			log.Printf("EVM代币Failed to load private key: %s", err)
			return nil, err
		}

		// value 转为 *big.Int
		v, ok := new(big.Int).SetString(value, 10)
		if !ok {
			return nil, err
		}
		signed, err := contract.GetTransactionSigned(client, privateKey, common.HexToAddress(tokenAddress), evmAbi.ERC20_ABI, "transfer", common.HexToAddress(to), v)
		if err != nil {
			return nil, err
		}

		return signed, nil
	} else {
		// value 转为 *big.Int
		v, ok := new(big.Int).SetString(value, 10)
		if !ok {
			return nil, errors.New("invalid value")
		}

		// 读取私钥
		feePrivateKey, err := utils.DecryptWithPrivateKeyFromFile(privateKeys.PrivateKey)
		if err != nil {
			return nil, err
		}

		client, err := ethclient.Dial(rpcUrl)
		if err != nil {
			return nil, err
		}

		privateKey, err := crypto.HexToECDSA(feePrivateKey)
		if err != nil {
			log.Printf("EVM主币Failed to load private key: %s", err)
			return nil, err
		}

		signed, err := contract.GetTransactionMainSigned(client, privateKey, v, common.HexToAddress(to))
		if err != nil {
			return nil, err
		}

		return signed, nil
	}
}

// GetTrxSign 获取TRX签名
func (s *SignService) GetTrxSign(privateKeys repositories.PrivateKeys, to string, tokenAddress string, value string, rpcUrl string) (string, error) {
	if tokenAddress == "" {
		v, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			return "", err
		}

		feePrivateKey, err := utils.DecryptWithPrivateKeyFromFile(privateKeys.PrivateKey)
		if err != nil {
			return "", err
		}
		signed, err := contract.GetTransactionTrxMainSigned(rpcUrl, feePrivateKey, v, to)
		if err != nil {
			return "", err
		}

		return signed, nil
	} else {
		withdrawPrivateKey, err := utils.DecryptWithPrivateKeyFromFile(privateKeys.PrivateKey)
		if err != nil {
			return "", err
		}

		// value 转为 int64
		v, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			return "", err
		}

		signed, err := contract.GetTransactionTrxSigned(rpcUrl, withdrawPrivateKey, v, to, tokenAddress)
		if err != nil {
			return "", err
		}
		return signed, nil
	}
}

// UpdateDecode 更新解码
func (s *SignService) UpdateDecode() error {
	// 生成新的秘钥对
	err := utils.GenerateRSAKeyPair()
	if err != nil {
		return errors.New("生成秘钥对失败")
	}

	var privateKeys repositories.PrivateKeys
	privateKeyList, err := privateKeys.FindAll()
	if err != nil {
		return err
	}
	var models []mongo.WriteModel
	for _, privateKey := range privateKeyList {
		// 使用旧的私钥解密
		decodePrivateKey, err := utils.DecryptWithOldPrivateKeyFromFile(privateKey.PrivateKey)
		if err != nil {
			return err
		}

		// 使用新的公钥加密
		encodePrivateKey, err := utils.EncryptWithPublicKeyFromFile(decodePrivateKey)
		if err != nil {
			return err
		}
		// 更新私钥
		id, _ := primitive.ObjectIDFromHex(privateKey.ID)
		model := mongo.NewUpdateOneModel().SetFilter(bson.M{"_id": id}).SetUpdate(bson.M{"$set": bson.M{"private_key": encodePrivateKey}})
		models = append(models, model)
	}

	if len(models) > 0 {
		err := privateKeys.BatchUpdate(models)
		if err != nil {
			_ = os.Rename("private_key_old.pem", "private_key.pem")
			_ = os.Rename("public_key_old.pem", "public_key.pem")
			return err
		}
	}
	return nil
}

// GetTokenForTokenSign 获取UU兑换签名
func (s *SignService) GetTokenForTokenSign(id string, rpcUrl string, to string, tokenAddress string, value string, flag int64) (*types.Transaction, error) {
	var chainConfig repositories.ChainUserConfig
	err := chainConfig.GetChainConfig(id)
	if err != nil {
		return nil, err
	}

	feePrivateKey, err := utils.DecryptWithPrivateKeyFromFile(chainConfig.FeePrivateKey)
	if err != nil {
		return nil, err
	}

	client, err := ethclient.Dial(rpcUrl)
	if err != nil {
		return nil, err
	}

	privateKey, err := crypto.HexToECDSA(feePrivateKey)
	if err != nil {
		log.Printf("EVM主币Failed to load private key: %s", err)
		return nil, err
	}

	// value 转为 *big.Int
	v, ok := new(big.Int).SetString(value, 10)
	if !ok {
		return nil, err
	}

	// flag 0公链币 1代币
	if flag == 0 {
		signed, err := contract.GetTransactionMainSigned(client, privateKey, v, common.HexToAddress(to))
		if err != nil {
			return nil, err
		}
		return signed, nil
	} else {
		signed, err := contract.GetTransactionSigned(client, privateKey, common.HexToAddress(tokenAddress), evmAbi.ERC20_ABI, "transfer", common.HexToAddress(to), v)
		if err != nil {
			return nil, err
		}

		return signed, nil
	}
}
